package com.michael.demos.base.thread.juc.lock;

/**
 * 类功能描述:
 * <pre>
 * 	可重入锁示例
 * 	实现原理:
 * 		通过为每个锁关联一个请求计数器和一个占有它的线程。当计数为0时，认为锁是未被占有的；
 *   	线程请求一个未被占有的锁时，JVM将记录锁的占有者，并且将请求计数器置为1;
 *      如果同一个线程再次请求这个锁，计数将递增；
 *      每次占用线程退出同步块，计数器值将递减。直到计数器为0,锁被释放。
 *
 * 	synchronized和ReentrantLock 都是可重入锁
 * </pre>
 *
 * @author Michael
 * @version 1.0
 * @date 2020/8/14 10:31
 */
public class ReentrantLockDemo {

	public static void main(String[] args) throws InterruptedException {
		ReentrantLockUse use = new ReentrantLockUse();
		// 以下代码正常执行
		use.willOK();
	}
}

class ReentrantLockUse {

	ReentrantLock lock = new ReentrantLock();

	public void willOK() throws InterruptedException {
		lock.lock();
		test();
		lock.unlock();
	}

	public void test() throws InterruptedException {
		lock.lock();
		//do something
		lock.unlock();
	}
}

class ReentrantLock {

	boolean isLocked = false;
	Thread lockedBy = null;
	// 锁计数器
	int lockedCount = 0;

	public synchronized void lock()
			throws InterruptedException {
		Thread thread = Thread.currentThread();
		while (isLocked && lockedBy != thread) {
			wait();
		}
		isLocked = true;
		lockedCount++;
		lockedBy = thread;
	}

	public synchronized void unlock() {
		if (Thread.currentThread() == this.lockedBy) {
			lockedCount--;
			if (lockedCount == 0) {
				isLocked = false;
				notify();
			}
		}
	}
}